home *** CD-ROM | disk | FTP | other *** search
- /********************************************************************/
- /* Program: XRef.c */
- /* This program comes from 'The C Programming Tutor' */
- /* by Leon A. Wortman and Thomas O. Sidebottom. */
- /* This program has typical UNIX interface and yields */
- /* a numbered listing and an alphabetized cross */
- /* reference listing with all reference line numbers */
- /* of all C identifiers used in the program. */
- /* */
- /* Modified for the Alpha Micro C by John Pence */
- /* compiles as a tool under MPW-Macintosh programers workshop also */
- /********************************************************************/
-
- /***********************************************************/
- /* Include Files */
- /***********************************************************/
- #include <stdio.h>
- #include <ctype.h>
-
- /***********************************************************/
- /* definitions */
- /***********************************************************/
- #define CR 13
- #define BOOL int
- #define DQUOTE '"'
- #define EQUALS 0
- #define FALSE 0
- #define FIRSTGREATER 1
- #define FIRSTLESS -1
- #define HTSIZE 1009 /* Must be a prime number */
- #define MAXSTRLEN 255
- #define MAXWORDSIZE 20
- #define SLASH '/'
- #define SQUOTE '\''
- #define STAR '*'
- #define TRUE 1
- #define VOID int
-
- /***********************************************************/
- /* code macros */
- /***********************************************************/
- #define PutBack(Ch) {PutBackChar = Ch; }
- #define GenerateNewIndex( x, y ) ( ( (x + y * y) % HTSIZE))
-
- /***********************************************************/
- /* typedefs */
- /***********************************************************/
- typedef struct rType {
- int Reference ; /* line number */
- struct rType *Link; /* link to next reference */
- }
- RefType, *RefPtr ;
-
- typedef struct tType {
- char *Value ; /* pointer to token */
- RefPtr OccurList ; /* line number list */
- }
- TokenType, *TokenPtr ;
-
- /***********************************************************/
- /* external functions */
- /***********************************************************/
- extern char *malloc() ;
- extern RefPtr MakeOccurrence() ;
-
- /***********************************************************/
- /* global variables */
- /***********************************************************/
- int CurLineNo = 1 ; /* Line being read */
- char OldChar, CurChar = '\0' ;
- TokenType HashTable[HTSIZE] ;
- int PutBackChar = '\0' ; /* Character put back after input */
-
- /***********************************************************/
- /* *** MAIN *** */
- /***********************************************************/
- main( argc, argv )
- int argc;
- char **argv ;
- { /* main */
- int Counter ;
- char CurToken [MAXSTRLEN] ;
- FILE *InFile ;
- /* There must be at least one command-line option.
- */
- if ( argc < 2 ) {
- fprintf(stderr, "USAGE: xref filename<cr>\n") ;
- exit(0);
- }
-
- if (!(InFile = fopen(argv[1],"r"))) {
- fprintf(stderr,"Can't open input file \"%s\".\n",argv[1]) ;
- exit(0) ;
- }
-
- /* Initialize the Hash Table.
- */
- for (Counter = 0; Counter < HTSIZE ; Counter++ ) {
- HashTable[Counter].Value = NULL ;
- HashTable[Counter].OccurList = NULL ;
- }
-
- /* Write the first line number to the output stream.
- */
- printf("\n%4d ",CurLineNo) ;
-
- /* Read and store each Token.
- */
- while (GetNxtToken(CurToken,InFile)) {
- if (InsertToken(CurToken)) {
- fprintf(stderr,"Hash Table size exceeded.\n") ;
- break ;
- } /* if */
- } /* while */
- printf("*** END OF FILE ***\n\n") ;
-
- /* Sort the Tokens alphabetically
- */
- SortTokens(HTSIZE) ;
-
- PrintTable() ;
- } /* main */
-
- /*==========================================================*/
- /* *** AddOccurrence() *** */
- /*==========================================================*/
- VOID AddOccurrence(HeadPtr)
- RefPtr HeadPtr ;
- /* AddOccurrence adds a new line to the
- * end of the list that HeadPtr begins.
- */
- { /* AddOccurrence */
- RefPtr CurPtr ;
- RefPtr NewPtr ;
-
- /* Find the end of the list by starting at
- * the begginning and advancing through the list
- * until we find the end.
- */
- for (CurPtr = HeadPtr; CurPtr->Link != NULL;
- CurPtr = CurPtr->Link)
- ;
-
- CurPtr->Link = NewPtr = (RefPtr)malloc(sizeof(RefType)) ;
- if (NewPtr == NULL) {
- fprintf(stderr,"Out of Memory in AddOccurrence.\0") ;
- exit(0) ;
- }
- NewPtr->Reference = CurLineNo ;
- NewPtr->Link = (RefPtr)NULL ;
- } /* AddOccurrence */
-
- /*==========================================================*/
- /* *** Copy() *** */
- /*==========================================================*/
- char *Copy(OldString)
- char *OldString ;
- /* Copy makes a copy of OldString and returns the address of
- * the copy.
- */
- { /* Copy */
- char *NewString ;
-
- /* Allocate a string able to hold the length
- * of the string plus one for the terminator.
- */
- NewString = malloc(strlen(OldString) +1) ;
-
- /* Copy the string and return a pointer to it.
- */
- strcpy(NewString,OldString) ;
- return(NewString) ;
- } /* Copy */
-
- /*==========================================================*/
- /* *** GetNxtChar() *** */
- /*==========================================================*/
- int GetNxtChar(InputFile)
- FILE *InputFile ;
- /* GetNxtChar returns the next non-comment
- * a non-string character from InputFile.
- *
- * At least one character is read from InputFile. If
- * the character could start a comment, the next character
- * is checked. If the slash-star of a comment
- * is read, the reading of characters continues until the end
- * of the comment is found. If a single or double quote
- * is read, the reading of characters continues until
- * the closing mark is found. When EOF is encountered,
- * EOF is returned. GetNxtChar therefore never returns
- * characters inside comments or quotes.
- */
- { /* GetNxtChar */
- int CheckChar ;
- int NewChar ;
- int TempChar ;
-
- /* If end-of-file is found, return immediately.
- */
- if ((NewChar = GetRawChar(InputFile)) == EOF)
- return (EOF) ;
-
- /* If a single or double quote is found, process the string.
- */
- if (NewChar == SQUOTE || NewChar == DQUOTE) {
- CheckChar = NewChar ;
- /* Continue reading until the matching quote character
- * is found.
- */
- do {
- if ((NewChar = GetRawChar(InputFile)) == '\\') {
- /* If LITERAL QUOTE is found in string;
- * ignore it.
- */
- while (((NewChar = GetRawChar(InputFile)) != EOF) &&
- (NewChar == DQUOTE)) ;
- continue;
- }
- } while (NewChar != CheckChar && NewChar != EOF) ;
- /* The terminating character has now been read.
- * Read one more and return it.
- */
- NewChar = GetRawChar(InputFile) ;
- }
-
- /* Next, handle comment processing. If SLASH is read,
- * check to see if the next character is a STAR. If it is,
- * continue reading until the next STAR-SLASH is found.
- */
- else if (NewChar == SLASH) {
- if ((TempChar = GetRawChar(InputFile)) != STAR) {
- /* Not a comment; putback the character.
- */
- PutBack(TempChar) ;
- }
- else
- /* Here's a comment. Search for the end.
- */
- do {
- /* Read characters until a STAR is found.
- */
- if (((NewChar = GetRawChar(InputFile)) == STAR) &&
- NewChar != EOF) {
- while (((NewChar = GetRawChar(InputFile)) == STAR) &&
- NewChar != EOF) ;
- if (NewChar == EOF)
- break;
- }
- } while (NewChar != SLASH && NewChar != EOF) ; /* do */
- NewChar = GetRawChar(InputFile) ;
- } /* else if */
- return (NewChar) ;
- } /* GetNxtChar */
-
- /*==========================================================*/
- /* *** GetNxtToken() *** */
- /*==========================================================*/
- BOOL GetNxtToken(Buffer, InputFile)
- char *Buffer ;
- FILE *InputFile ;
- /* GetNxtToken returns in Buffer, the next valid C token in the
- * program.
- */
- { /* GetNxtToken */
- int CurChar, OldChar ;
-
- /* Read the characters from the InputFile until starting letter is
- * found. Stop when a valid letter or end-of-file is found.
- */
- while (!IsStartingLetter(CurChar = GetNxtChar(InputFile), OldChar) &&
- CurChar != EOF)
- OldChar = CurChar;
-
- /* Read the first character.
- */
- *Buffer++ = CurChar ;
-
- /* Read and accumulate characters in buffer while they are
- * valid letters for a token.
- */
- while (IsTokenLetter(CurChar = GetNxtChar(InputFile)) &&
- CurChar != EOF)
- *Buffer++ = CurChar ;
-
- /* Put back the last character we read.
- */
- if (CurChar != EOF)
- PutBack(CurChar) ;
-
- /* Terminate the Token.
- */
- *Buffer = '\0' ;
-
- /* Return end-of-file status.
- */
- return ((CurChar == EOF) ? FALSE : TRUE) ;
- } /* GetNxtToken */
-
- /*==========================================================*/
- /* *** GetRawChar() *** */
- /*==========================================================*/
- int GetRawChar(InputFile)
- FILE *InputFile ;
- /* GetRawChar reads the next character fromn the InputFile and
- * returns it. If a newline is read, it increments
- * CurLineNo. If end-of-file is read, it returns EOF.
- */
- { /* GetRawChar */
- int NextChar ;
- /* Check PutBackChar to see if the next character has
- * already been read. If so, process it and set PutBackChar
- * to the NULL character.
- */
- if (PutBackChar != '\0') {
- NextChar = PutBackChar ;
- PutBackChar = '\0' ;
- }
- else {
- /* Echo the character read to the output stream.
- * If a CR is read, increment the line count.
- */
- if ((NextChar = getc(InputFile)) == '\n')
- printf("\n%4d ", ++CurLineNo) ;
- else {
- if (NextChar != EOF)
- putchar(NextChar) ;
- }
- }
-
- if (NextChar == EOF)
- return (EOF) ;
-
- return (NextChar) ;
- } /* GetRawChar */
-
- /*==========================================================*/
- /* *** Hash() *** */
- /*==========================================================*/
- int Hash(Word)
- char *Word ;
- /* Hash returns the HTIndex of the Word passed, or an
- * appropriate HTIndex for the Word. If HashTable is
- * full, Hash returns -1.
- */
- { /* Hash */
- int HTIndex ;
- int IdLen ;
- int InitHTIndex ;
- int ProbeCounter = 0 ;
-
- IdLen = strlen(Word) ;
- if (IdLen == 0)
- printf("Hash: Word of no length\n") ;
- HTIndex = InitHTIndex = TransformId(Word) ;
- if (HashTable[HTIndex].Value == NULL)
- ; /* no-op - We've got it. */
- else /* Have we found the correct index? */
-
- if (strcmp(Word,HashTable[HTIndex].Value) == EQUALS)
- ; /* DONE: A direct hit! */
-
- else /* Collision -- generate indexes */
- for (ProbeCounter=0; ProbeCounter<(HTSIZE / 2);
- ProbeCounter++) {
- HTIndex = GenerateNewIndex(InitHTIndex, ProbeCounter) ;
- if (HashTable[HTIndex].Value == NULL)
- break ; /* We've got it ! */
- else if (strcmp(Word,HashTable[HTIndex].Value)
- == EQUALS)
- break ; /* We've got it ! */
- }
-
- if (ProbeCounter >= (HTSIZE / 2))
- return(-1) ;
- return(HTIndex) ;
- } /* Hash */
-
- /*==========================================================*/
- /* *** InsertToken() *** */
- /*==========================================================*/
- BOOL InsertToken(Token)
- char *Token ;
- /* Inserts the Token into the hash table if it is new. If
- * the Token is previously known, it adds the line number
- * to the occurrence list. It then returns FALSE.
- * If the end-of-hash table is reached, TRUE is returned.
- */
- { /* InsertToken */
- int HTIndex ;
-
- HTIndex = Hash(Token) ;
- if (HTIndex == -1)
- return(TRUE) ;
-
- if (HashTable[HTIndex].Value == NULL) {
- HashTable[HTIndex].Value = Copy(Token) ;
- HashTable[HTIndex].OccurList = MakeOccurrence() ;
- }
- else
- AddOccurrence(HashTable[HTIndex].OccurList) ;
-
- return(FALSE) ;
- } /* InsertToken */
-
- /*==========================================================*/
- /* *** IsStartingLetter() *** */
- /*==========================================================*/
- BOOL IsStartingLetter(Ch, Ch2)
- char Ch, Ch2 ;
- /* IsStartingLetter returns TRUE if Ch is a valid character to
- * begin a C token.
- */
- { /* IsStartingLetter */
- return (((isalpha(Ch) || Ch == '_') &&
- (!isdigit(Ch2))) ? TRUE : FALSE) ;
- } /* IsStartingLetter */
-
- /*==========================================================*/
- /* *** IsTokenLetter() *** */
- /*==========================================================*/
- BOOL IsTokenLetter(Ch)
- char Ch ;
- /* IsTokenLetter returns TRUE if Ch is a valid character
- * inside a C token.
- */
- { /* IsTokenLetter */
- return ((isalpha(Ch) || isdigit(Ch) || Ch == '_') ? TRUE : FALSE) ;
- } /* IsTokenLetter */
-
- /*==========================================================*/
- /* *** MakeOccurrence() *** */
- /*==========================================================*/
- RefPtr MakeOccurrence()
- /* MakeOccurrence creates the first entry of the line occurrence
- * list. It creates the next node in the list, inserts CurLineNo
- * and sets Link to NULL in preparation for the next entry.
- */
- { /* MakeOccurrence */
- RefPtr NewNode ;
-
- if ((NewNode = (RefPtr)malloc(sizeof(RefType))) == NULL) {
- fprintf(stderr,"Out of Memory in MakeOccurrence.\n") ;
- exit(0) ;
- }
- NewNode->Reference = CurLineNo ;
- NewNode->Link = (RefPtr)NULL ;
-
- return (NewNode) ;
- } /* MakeOccurrence */
-
- /*==========================================================*/
- /* *** NameCompare() *** */
- /*==========================================================*/
- int NameCompare(First,Second)
- int First ;
- int Second ;
- /* NameCompare compares two entries in HashTable referenced
- * by the indices First and Second. It returns FIRSTLESS if
- * First < Second; EQUALS if they are equal;
- * and FIRSTGREATER if First > Second.
- */
- { /* NameCompare */
- /* If the first entry has no value, the first is less.
- */
- if (HashTable[First].Value == NULL)
- return (FIRSTLESS) ;
-
- /* Then if the second has no value, the first is greater.
- */
- if (HashTable[Second].Value == NULL)
- return (FIRSTGREATER) ;
-
- /* Otherwise return the comparison from strcmp.
- */
- return (strcmp(HashTable[First].Value, HashTable[Second].Value)) ;
- } /* NameCompare */
-
- /*==========================================================*/
- /* *** PrintTable() *** */
- /*==========================================================*/
- VOID PrintTable()
- /* PrintTable prints the list of identifiers and line occurrences.
- */
- { /* PrintTable */
- RefPtr ListPtr ;
- int NumOnLine ;
- int TokenCounter ;
-
- for (TokenCounter = 0 ; TokenCounter < HTSIZE ;
- TokenCounter++) {
- if (HashTable[TokenCounter].Value) {
- printf("\n%-20s ",HashTable[TokenCounter].Value) ;
- for (ListPtr = HashTable[TokenCounter].OccurList, NumOnLine = 0;
- ListPtr != NULL;
- ListPtr = ListPtr->Link, NumOnLine++ ) {
- if (NumOnLine == 10) {
- printf("\n ") ;
- NumOnLine = 0 ;
- }
- printf("%3d ", ListPtr->Reference) ;
- }
- }
- }
- printf("\n") ;
- } /* PrintTable */
-
- /*==========================================================*/
- /* *** SortTokens() *** */
- /*==========================================================*/
- VOID SortTokens(SortNumber)
- int SortNumber ;
- /* SortTokens sorts the tokens into alphabetical order
- * using a shell sort.
- */
- { /* SortTokens */
- TokenType Exchange ;
- int BaseCounter ;
- int CurCounter ;
- int CurGapCounter ;
- int Gap ;
- int LastInBuf ;
-
- LastInBuf = SortNumber ;
- /* Look through all Gaps starting with a gap half the
- * size of the list. Each time reduce the size of the gap
- * by dividing by two.
- */
- for (Gap = LastInBuf / 2; Gap > 0; Gap /= 2)
-
- /* BaseCounter moves between the Gap-th element and
- * the last element in the list. The sort using the
- * current Gap runs until 1 is the LastInBuf-th
- * element in the list.
- */
- for (BaseCounter = Gap; BaseCounter < LastInBuf; BaseCounter++)
-
- /* For a BaseCounter, we compare the CurCounter-th and
- * the CurGapCounter-th elements in the list. CurCounter
- * and CurGapCounter are always separated by Gap.
- */
- for (CurCounter = BaseCounter - Gap; CurCounter >= 0; CurCounter -= Gap) {
- CurGapCounter = CurCounter + Gap ;
-
- /* If the two elements compare correctly, stop.
- */
- if (NameCompare(CurCounter, CurGapCounter) < EQUALS)
- break;
-
- /* Otherwise, exchange the elements.
- */
- Exchange.Value = HashTable[CurCounter].Value ;
- Exchange.OccurList = HashTable[CurCounter].OccurList ;
- HashTable[CurCounter].Value = HashTable[CurGapCounter].Value ;
- HashTable[CurCounter].OccurList = HashTable[CurGapCounter].OccurList ;
- HashTable[CurGapCounter].Value = Exchange.Value ;
- HashTable[CurGapCounter].OccurList = Exchange.OccurList ;
- }
- } /* SortTokens */
-
- /*==========================================================*/
- /* *** TransformID() *** */
- /*==========================================================*/
- int TransformId(Word)
- char Word[] ;
- /* Converts an identifier into an integer within the index
- * range of HashTable. A polynomial is generated and reduced
- * modulo HTSIZE to produce this number.
- */
- { /* TransformId */
- int Term = 0 ;
- int WordIndex ;
-
- for (WordIndex = strlen(Word)-1 ; (WordIndex >= 0) ; WordIndex--)
- Term = (257*Term) + Word[ WordIndex ] ;
-
- Term = (Term < 0 ) ? -Term : Term ;
- return(Term % HTSIZE) ;
- } /* TransformId */